using System;
using System.Data;
using System.IO;
using System.Runtime.Remoting;

namespace CodeDomAssistant
{
    public class DynProvider
    {
        static public DataSet GetAssemblyInfo()
        {
            DataSet data = new DataSet();
            data.DataSetName = "AssemblyDataSet";

            DataTable table = data.Tables.Add("Assembly");

            table.Columns.Add("Load", typeof(bool));
            table.Columns.Add("Name", typeof(string));
            table.Columns.Add("Path", typeof(string));
            table.Columns.Add("IsGAC", typeof(bool));
            table.Columns.Add("HasProvider", typeof(bool));

            string localpath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CodeDomAssistant");
            if (!Directory.Exists(localpath))
            {
                Directory.CreateDirectory(localpath);
            }

            string assemblydatafile = Path.Combine(localpath, "AssemblyData.xml");
            if (File.Exists(assemblydatafile))
            {
                data.ReadXml(assemblydatafile);
            }

            data.AcceptChanges();
 
            return data;
        }

        static public void SaveAssemblyInfo(DataSet assemblydata)
        {
            string localpath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CodeDomAssistant");
            if (!Directory.Exists(localpath))
            {
                Directory.CreateDirectory(localpath);
            }

            string assemblydatafile = Path.Combine(localpath, "AssemblyData.xml");
            assemblydata.WriteXml(assemblydatafile);

            assemblydata.AcceptChanges();
        }

        static public void MergeLocal(DataSet assemblydata, string assemblyfile, Progress progress)
        {
            DataRow assemblyInfo = null;
            bool updated = false;
            bool hasprovider = false;

            AppDomain appdomain = null;

            try
            {
                if (progress != null)
                {
                    progress.Message = string.Format("Scanning DLL: {0}", Path.GetFileName(assemblyfile));
                    progress.Notify();
                }

                AppDomainSetup setup = new AppDomainSetup();
                setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

                appdomain = AppDomain.CreateDomain("TestCodeDomProviders", null, setup);

                ObjectHandle handle = appdomain.CreateInstance("RemoteLoader", "RemoteLoader.RemoteLoaderFactory");

                RemoteLoader.RemoteLoaderFactory factory = (RemoteLoader.RemoteLoaderFactory)handle.Unwrap();

                string name = factory.GetAssemblyName(assemblyfile);
                if (name != null)
                {
                    hasprovider = factory.IsSubclassOfCodeDomProvider(assemblyfile);

                    DataRow[] rows = assemblydata.Tables[0].Select(string.Format(@"Path = '{0}'", assemblyfile));
                    if (rows.Length == 0)
                        assemblyInfo = assemblydata.Tables[0].NewRow();
                    else
                        assemblyInfo = rows[0];

                    assemblyInfo["Load"] = false;
                    assemblyInfo["Name"] = name;
                    assemblyInfo["Path"] = assemblyfile;
                    assemblyInfo["IsGAC"] = false;
                    assemblyInfo["HasProvider"] = hasprovider;

                    if (rows.Length == 0)
                    {
                        assemblydata.Tables[0].Rows.Add(assemblyInfo);
                    }

                    updated = true;
                }
            }
            finally
            {
                if (appdomain != null)
                {
                    AppDomain.Unload(appdomain);
                }
            }
        }

        static public void MergeGAC(DataSet assemblydata, bool refreshcache, Progress progress)
        {
            bool updated = false;

            AppDomain appdomain = null;

            try
            {
                AppDomainSetup setup = new AppDomainSetup();
                setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

                appdomain = AppDomain.CreateDomain("FindCodeDomProviders", null, setup);

                ObjectHandle handle = appdomain.CreateInstance("RemoteLoader", "RemoteLoader.RemoteLoaderFactory");

                RemoteLoader.RemoteLoaderFactory factory = (RemoteLoader.RemoteLoaderFactory)handle.Unwrap();

                string strGacDir = Path.Combine(System.Environment.ExpandEnvironmentVariables("%windir%"), @"assembly\GAC");

                string[] gac = System.IO.Directory.GetDirectories(strGacDir);
                foreach (string dir in gac)
                {
                    if (progress != null)
                    {
                        progress.Message = string.Format("Scanning GAC: {0}", Path.GetFileName(dir));
                        progress.Notify();
                    }

                    string[] assDirs = System.IO.Directory.GetDirectories(dir);
                    foreach (string dir2 in assDirs)
                    {

                        string[] files = System.IO.Directory.GetFiles(dir2, "*.dll");
                        foreach (string assemblyfile in files)
                        {
                            DataRow[] rows = assemblydata.Tables[0].Select(string.Format(@"Path = '{0}'", assemblyfile));
                            if (rows.Length == 0 || refreshcache)
                            {
                                string name = factory.GetAssemblyName(assemblyfile);
                                if (name != null)
                                {
                                    bool hasprovider = factory.IsSubclassOfCodeDomProvider(assemblyfile);

                                    DataRow assemblyInfo = null;

                                    if (rows.Length == 0)
                                        assemblyInfo = assemblydata.Tables[0].NewRow();
                                    else
                                        assemblyInfo = rows[0];

                                    assemblyInfo = assemblydata.Tables[0].NewRow();
                                    assemblyInfo["Load"] = false;
                                    assemblyInfo["Name"] = name;
                                    assemblyInfo["Path"] = assemblyfile;
                                    assemblyInfo["IsGAC"] = true;
                                    assemblyInfo["HasProvider"] = hasprovider;


                                    if (rows.Length == 0)
                                    {
                                        assemblydata.Tables[0].Rows.Add(assemblyInfo);
                                    }

                                    updated = true;
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                if (appdomain != null)
                {
                    AppDomain.Unload(appdomain);
                }
            }
        }
    }
}
